import json
import traceback
from django.http import JsonResponse
from django.views.generic import View
from ..serializers.quantitySerializer import *
from django.db.models import Q
from django.core.paginator import Paginator
from utils.encryptionAndDecryptionUtil import get_user_from_useraccount, get_useraccount_from_request
from ..config.message_config import *
from ..utils.common_util.basic_util import get_order_list_combined
from ..utils.related_util.used_util import is_unit_used
from django.db import IntegrityError, transaction
from basic_component_related_management.models import *
from utils.responseContentUtil import *


class QuantityView(View):
    def get(self, request):
        res = {"code": 400, "message": "", "data": None}
        try:
            data = request.GET
            query_list_serializer = QuantityListQuerySerializer(data=data)
            data_valid = query_list_serializer.is_valid()
            if not data_valid:
                return make_get_error_response(message=query_list_serializer.errors)
            data = query_list_serializer.validated_data
            query = Q()
            query &= Q(valid_flag=True)
            if "quantity_name" in data:
                query &= (Q(quantity_name__icontains=data["quantity_name"]) | Q(
                    quantity_name_en__icontains=data["quantity_name"]))
            if "sei_id" in data:
                query &= Q(sei_id__icontains=data["sei_id"])
            if "quantity_symbol" in data:
                query &= Q(quantity_symbol__icontains=data["quantity_symbol"])
            if "dimension" in data:
                query &= Q(dimension=data["dimension"])
            order_list_combined = get_order_list_combined(data)
            if len(order_list_combined) == 0:
                quantities = Quantity.objects.filter(
                    query).order_by("-create_date")
            else:
                quantities = Quantity.objects.filter(
                    query).order_by(*order_list_combined)
            page_size = data["page_size"]
            current_page = data["current_page"]
            total_count = quantities.count()
            paginator = Paginator(quantities, page_size)
            if current_page > paginator.num_pages:
                current_page = paginator.num_pages
            page_obj = paginator.get_page(current_page)
            res_data = {}
            res_data["current_page"] = current_page
            res_data["page_size"] = page_size
            res_data["total_count"] = total_count
            quantity_list_serializer = QuantityListSerializer(
                page_obj, many=True)
            res_data["objects"] = quantity_list_serializer.data
            return make_get_success_response(data=res_data)
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))

    def post(self, request):
        res = {"code": 400, "message": "", "data": None}
        try:
            user_name = get_useraccount_from_request(request)
            user = get_user_from_useraccount(user_name)
            data = json.loads(request.body)
            create_serializer = QuantityCreateSerializer(data=data)
            data_valid = create_serializer.is_valid()
            if not data_valid:
                res["code"] = 400
                res_message = "参数错误:\n"
                if "quantity_name" in create_serializer.errors:
                    res_message += "量中文名称已存在;\n"
                if "quantity_name_en" in create_serializer.errors:
                    res_message += "量英文名称已存在;\n"
                if "sei_id" in create_serializer.errors:
                    res_message += "编码已存在;\n"
                return make_create_error_response(message=res_message)
            data = create_serializer.validated_data
            data["dimension"] = Dimension.objects.filter(
                uuid=data["dimension"], valid_flag=True).first()
            quantity = Quantity.objects.create(
                **data, create_person=user, modify_person=user)
            return make_create_success_response(data=quantity.uuid)
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))


class QuantityInfoView(View):
    def get(self, request, uuid):
        res = {"code": 400, "message": "", "data": None}
        try:
            get_params = request.GET
            info_get_type = get_params.get("type", "")
            quantity = Quantity.objects.filter(
                uuid=uuid, valid_flag=True).first()
            if quantity is None:
                return make_get_error_response(message="该量不存在")
            if info_get_type == "modify":
                quantity_serializer = QuantityModifyInfoSerializer(quantity)
            else:
                quantity_serializer = QuantityInfoSerializer(quantity)
            return make_get_success_response(data=quantity_serializer.data)
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))

    def put(self, request, uuid):
        res = {"code": 400, "message": "", "data": None}
        try:
            user_name = get_useraccount_from_request(request)
            user_name = get_user_from_useraccount(user_name)
            data = json.loads(request.body)
            quantity = Quantity.objects.filter(
                uuid=uuid, valid_flag=True).first()
            if quantity is None:
                return make_update_error_response(message="该量不存在")
            modify_serializer = QuantityModifyInfoInSerializer(
                quantity, data=data)
            data_valid = modify_serializer.is_valid()
            if not data_valid:
                res["code"] = 400
                res_message = "参数错误:\n"
                if "quantity_name" in modify_serializer.errors:
                    res_message += "量中文名称已存在;\n"
                if "quantity_name_en" in modify_serializer.errors:
                    res_message += "量英文名称已存在;\n"
                if "sei_id" in modify_serializer.errors:
                    res_message += "编码已存在;\n"
                return make_update_error_response(message=res_message)
            data = modify_serializer.validated_data
            data["dimension"] = Dimension.objects.filter(
                uuid=data["dimension"], valid_flag=True).first()
            dimension_same_flag = True
            if quantity.dimension != data["dimension"]:
                dimension_same_flag = False
            try:
                with transaction.atomic():
                    for key in data:
                        setattr(quantity, key, data[key])
                    quantity.modify_person = user_name
                    quantity.save()
                    if not dimension_same_flag:
                        quantity_unit_maps = quantity.quantity_unit_map_quantity.all()
                        for quantity_unit_map in quantity_unit_maps:
                            quantity_unit_map.delete()
            except IntegrityError as e:
                return make_update_error_response(message="违背约束" + str(e))
            return make_update_success_response() 
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))

    def delete(self, request, uuid):
        res = {"code": 400, "message": "", "data": None}
        try:
            user_name = get_useraccount_from_request(request)
            user_name = get_user_from_useraccount(user_name)
            quantity = Quantity.objects.filter(
                uuid=uuid, valid_flag=True).first()
            if quantity is None:
                return make_delete_error_response(message="该量不存在")
            # 判断物理量是否被物性、常量物性、物性变量引用
            propertys = Property.objects.filter(
                quantity=quantity, valid_flag=True).all()
            if len(propertys) > 0:
                return make_delete_error_response(message="物理量被物性引用，无法删除")
            const_propertys = ComponentConstProperty.objects.filter(
                quantity=quantity, valid_flag=True).all()
            if len(const_propertys) > 0:
                return make_delete_error_response(message="物理量被推荐物性引用，无法删除")
            variable_propertys = PropertyVariable.objects.filter(
                quantity=quantity, valid_flag=True).all()
            if len(variable_propertys) > 0:
                return make_delete_error_response(message="物理量被物性变量引用，无法删除")

            quantity.valid_flag = False
            quantity.modify_person = user_name
            quantity.save()
            return make_delete_success_response()
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))


class QuantityUnitView(View):
    def get(self, request, uuid):
        res = {"code": 400, "message": "", "data": None}
        try:
            quantity = Quantity.objects.filter(
                uuid=uuid, valid_flag=True).first()
            if quantity is None:
                return make_get_error_response(message="该量不存在")
            quantity_unit_maps = quantity.quantity_unit_map_quantity.all()
            unit_list = []
            for quantity_unit_map in quantity_unit_maps:
                if quantity_unit_map.unit.valid_flag:
                    unit_list.append(quantity_unit_map.unit.uuid)
            data = {
                "available_units": unit_list
            }
            return make_get_success_response(data=data)
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))

    def put(self, request, uuid):
        res = {"code": 400, "message": "", "data": None}
        try:
            user_name = get_useraccount_from_request(request)
            user_name = get_user_from_useraccount(user_name)
            data = json.loads(request.body)
            quantity = Quantity.objects.filter(
                uuid=uuid, valid_flag=True).first()
            if quantity is None:
                return make_update_error_response(message="该量不存在")
            available_units = data["available_units"]
            quantity_unit_add = []
            quantity_unit_delete = []
            before_units = quantity.quantity_unit_map_quantity.all()
            for before_unit in before_units:
                if before_unit.unit.uuid in available_units:
                    available_units.remove(before_unit.unit.uuid)
                else:
                    quantity_unit_delete.append(before_unit)
            for available_unit in available_units:
                unit = Unit.objects.filter(
                    uuid=available_unit, valid_flag=True).first()
                if unit is None:
                    return make_update_error_response(message="单位不存在")
                quantity_unit_map_data = {
                    "quantity": quantity,
                    "unit": unit
                }
                quantity_unit_map = QuantityUnitMap(**quantity_unit_map_data)
                quantity_unit_add.append(quantity_unit_map)
            try:
                with transaction.atomic():
                    QuantityUnitMap.objects.bulk_create(quantity_unit_add)
                    for quantity_unit in quantity_unit_delete:
                        quantity_unit.delete()
            except IntegrityError as e:
                return make_update_error_response(message="违背约束" + str(e))
            return make_update_success_response()
        except Exception as e:
            traceback.print_exc()
            return make_server_error_response(str(e))
